home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / fontutil.6 / fontutil / fontutils-0.6 / widgets / Fontview.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-27  |  15.6 KB  |  477 lines

  1. /* Fontview.c: implementation of a Fontview widget.
  2.  
  3. Copyright (C) 1992 Free Software Foundation, Inc.
  4.  
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include "xt-common.h"
  22.  
  23.  
  24. #include "char.h"
  25. #include "font.h"
  26. #include "FontviewP.h"
  27.  
  28. /* Utility routines.  */
  29. static Pixmap bitmap_to_pixmap (Display *, GC, bitmap_type);
  30. static charcode_type find_keycode (XEvent *, boolean *);
  31.  
  32.  
  33.  
  34. /* Action routines.  */
  35.  
  36. static action_proc_type self_insert;
  37.  
  38. /* The mapping of action names to procedures.  */
  39. static XtActionsRec fontview_actions[]
  40.   = { { "SelfInsert", self_insert },
  41.     };
  42.  
  43. /* This structure defines the default values of the resources specific
  44.    to the Bitmap widget.  */
  45. #define OFFSET(field) XtOffset (FontviewWidget, fontview.field)
  46. static XtResource fontview_resources[]
  47.   = { IMMEDIATE_RESOURCE (chars, CharInfo, Pointer, NULL),
  48.       IMMEDIATE_RESOURCE2 (fontInfo, font_info, FontInfo, Pointer, NULL),
  49.       IMMEDIATE_RESOURCE2 (lineSpace, line_space, Fontdimen, Dimension,
  50.                            FONTVIEW_DEFAULT_LINE_SPACE),
  51.       IMMEDIATE_RESOURCE2 (wordSpace, word_space, Fontdimen, Dimension,
  52.                            FONTVIEW_DEFAULT_WORD_SPACE),
  53.       IMMEDIATE_RESOURCE (resolution, Resolution, Dimension,
  54.                           FONTVIEW_DEFAULT_RESOLUTION),
  55.     };
  56.  
  57.  
  58. /* Routines in the class record.  */
  59. static void fontview_initialize (Widget, Widget, ArgList, Cardinal *);
  60. static void fontview_resize (Widget);
  61. static Boolean fontview_set_values (Widget, Widget, Widget, ArgList,
  62.                                     Cardinal *);
  63. static void fontview_destroy (Widget);
  64.  
  65. /* We can inherit most things in the instantiation of the class record.
  66.    The operations `initialize', `set_values', and `destroy' are chained
  67.    automatically by the toolkit, and need no `XtInherit...' constant.  */
  68.  
  69. FontviewClassRec fontviewClassRec
  70.   = { /* Core class fields.  */
  71.       { /* superclass           */ (WidgetClass) &labelClassRec,
  72.         /* class_name           */ "Fontview",
  73.         /* widget_size           */ sizeof (FontviewRec),
  74.         /* class_initialize        */ NULL,
  75.         /* class_part_initialize */ NULL,
  76.         /* class_inited            */ FALSE,
  77.         /* initialize           */ fontview_initialize,
  78.         /* initialize_hook     */ NULL,
  79.         /* realize         */ XtInheritRealize,
  80.         /* actions         */ fontview_actions,
  81.         /* num_actions           */ XtNumber (fontview_actions),
  82.         /* resources           */ fontview_resources,
  83.         /* num_resources     */ XtNumber (fontview_resources),
  84.         /* xrm_class           */ NULLQUARK,
  85.         /* compress_motion     */ TRUE,
  86.         /* compress_exposure       */ TRUE,
  87.         /* compress_enterleave     */ TRUE,
  88.         /* visible_interest     */ FALSE,
  89.         /* destroy         */ fontview_destroy,
  90.         /* resize         */ fontview_resize,
  91.         /* expose         */ XtInheritExpose,
  92.         /* set_values           */ fontview_set_values,
  93.         /* set_values_hook     */ NULL,
  94.         /* set_values_almost     */ XtInheritSetValuesAlmost,
  95.         /* get_values_hook     */ NULL,
  96.         /* accept_focus          */ NULL,
  97.         /* version         */ XtVersion,
  98.         /* callback_private        */ NULL,
  99.         /* tm_table         */ NULL,
  100.         /* query_geometry     */ XtInheritQueryGeometry,
  101.         /* display_accelerator     */ XtInheritDisplayAccelerator,
  102.         /* extension         */ NULL
  103.       },
  104.  
  105.       /* Simple class fields.  */
  106.       { /* change_sensitive */ XtInheritChangeSensitive },
  107.  
  108.       /* Label class fields.  */
  109.       { 0 },
  110.  
  111.       /* Fontview class fields.  */
  112.       { 0 }
  113.     };
  114.  
  115. WidgetClass fontviewWidgetClass = (WidgetClass) &fontviewClassRec;
  116.  
  117.  
  118.  
  119. /* Class routines.  */
  120.  
  121. /* This routine is called at widget creation time by the toolkit, after
  122.    our superclasses have been initialized.  REQUEST is the widget that
  123.    was originally requested by the user; NEW is the widget that has been
  124.    created by our superclasses in response to the requests.
  125.    
  126.    We want to tell our Label superclass that it should deal with a pixmap,
  127.    not with a string.  */
  128.  
  129. #define DEPTH 1 /* No grayscale or color bitmaps.  */
  130. #define HEIGHT_PERCENT .65 /* Percent of line_space above baseline.  */
  131.  
  132. static void
  133. fontview_initialize (Widget request, Widget new, ArgList args,
  134.                      Cardinal *n_args) 
  135. {
  136.   XGCValues gc_values;
  137.   FontviewWidget fw = (FontviewWidget) new;
  138.   Display *d = XtDisplay (fw);
  139.   
  140.   /* Assume the width and height resources in the label have been set to
  141.      reflect how big the canvas is supposed to be.  */
  142.   unsigned width = fw->core.width;
  143.   unsigned height = fw->core.height;
  144.   
  145.   /* What we'll draw in.  */
  146.   Pixmap pixmap
  147.     = XCreatePixmap (d, DefaultRootWindow (d), width, height, DEPTH);
  148.   
  149.   Arg label_args[]
  150.     = { { XtNbitmap, pixmap },
  151.         { XtNheight, height },
  152.         { XtNwidth, width },
  153.       };
  154.  
  155.   if (pixmap == None)
  156.     XtErrorMsg ("noPixmap", "FontviewWidget", "Error",
  157.                 "Can't allocate pixmap to show character", NULL, 0);
  158.  
  159.   XtSetValues (fw, XTARG (label_args));
  160.   
  161.   fw->fontview.current_char = NULL;
  162.   fw->fontview.current_pos.x = 0;
  163.   fw->fontview.current_pos.y = HEIGHT_PERCENT * fw->fontview.line_space;
  164.  
  165.   /* Leave the foreground as zero, since we always clear before we draw
  166.      something.  */
  167.   gc_values.background = 0L;
  168.   fw->fontview.gc
  169.     = XCreateGC (d, fw->label.pixmap, GCBackground, &gc_values);
  170.   
  171.   XFillRectangle (d, fw->label.pixmap, fw->fontview.gc, 0, 0, width, height);
  172. }
  173.  
  174.  
  175. /* When we are resized, we have to change the size of the pixmap.  */
  176.  
  177. static void
  178. fontview_resize (Widget w)
  179. {
  180.   FontviewWidget fw = (FontviewWidget) w;
  181.   Display *d = XtDisplay (fw);
  182.   
  183.   /* The width and height of W have been set.  */
  184.   unsigned new_width = fw->core.width - fw->label.internal_width * 2;
  185.   unsigned new_height = fw->core.height - fw->label.internal_height * 2;
  186.   Pixmap pixmap;
  187.   
  188.   /* Get the old width and height of the Label's pixmap.  */
  189.   unsigned old_width, old_height, bw, depth;
  190.   Window root;
  191.   int x, y;
  192.  
  193.   /* The Label's initialize procedure calls resize directly.  I don't
  194.      know whether it should or not, but since it does, we might get
  195.      called before the pixmap is set up.  If so, we have nothing to do.  */
  196.   if (fw->label.pixmap != None)
  197.     {
  198.       assert (XGetGeometry (d, fw->label.pixmap, &root, &x, &y, &old_width,
  199.                             &old_height, &bw, &depth));
  200.  
  201.       /* Since the SetValues call below winds up resizing the Label, we
  202.          are going to be called again.  So only do any resizing if the
  203.          size is actually different.  */
  204.       if (new_width != old_width || new_height != old_height)
  205.         {
  206.           pixmap = XCreatePixmap (d, DefaultRootWindow (d), new_width,
  207.                                   new_height, DEPTH);
  208.  
  209.           /* Copy the contents of the old pixmap to the new.  */
  210.           XCopyArea (d, fw->label.pixmap, pixmap, fw->fontview.gc, 0, 0,
  211.                      MIN (old_width, new_width), MIN (old_height, new_height),
  212.                      0, 0);
  213.  
  214.           /* Free the old pixmap, and set the Label's pixmap to the new.  */
  215.           XFreePixmap (d, fw->label.pixmap);
  216.           XtVaSetValues (w, XtNbitmap, pixmap, NULL, NULL);
  217.         }
  218.     }
  219. }
  220.  
  221.  
  222. /* This routine is called when one of the resources in the widget
  223.    changes; for example, in response to an XtSetValues call.  */
  224.  
  225. static Boolean
  226. fontview_set_values (Widget current, Widget request, Widget new,
  227.                      ArgList args, Cardinal *n_args)
  228. {
  229.   return False;
  230. }
  231.  
  232.  
  233. /* This routine is called when the widget is destroyed.  */
  234.  
  235. static void
  236. fontview_destroy (Widget w)
  237. {
  238.   FontviewWidget fw = (FontviewWidget) w;
  239.   
  240.   XFreeGC (XtDisplay (fw), fw->fontview.gc);
  241. }
  242.  
  243.  
  244.  
  245. /* These convenience procedures save clients the trouble of constructing
  246.    an ArgList to get the resources in the widget.  (None yet.)  */
  247.  
  248.  
  249.  
  250. /* Action procedures.  */
  251.  
  252. /* Display the character specified in the (presumably Key) event EVENT.
  253.    Kern, if appropriate, between that character and the previous current
  254.    character (but don't do ligature processing, and don't worry about
  255.    the ligtable ``cursor advancing'' commands).  Then set the new
  256.    current character.  */
  257.  
  258. static void
  259. self_insert (Widget w, XEvent *event, String *params, Cardinal *n_params)
  260. {
  261.   char_info_type bitmap_info;
  262.   char_type *c;
  263.   boolean found;
  264.   int kern;
  265.   Pixmap pixmap;
  266.   int final_y;
  267.   FontviewWidget fw = (FontviewWidget) w;
  268.   Display *d = XtDisplay (fw);
  269.   char_type **chars = (char_type **) fw->fontview.chars;
  270.   char_type *current = fw->fontview.current_char;
  271.   coordinate_type current_pos = fw->fontview.current_pos;
  272.   font_type *font = (font_type *) fw->fontview.font_info;
  273.   GC gc = fw->fontview.gc; /* Assume the function is GXclear.  */
  274.   int test_x = fw->fontview.current_pos.x;
  275.   unsigned height = fw->core.height;
  276.   unsigned width = fw->core.width;
  277.   charcode_type code = find_keycode (event, &found);
  278.   
  279.   /* If no character code in the key event, do nothing.  */
  280.   if (!found)
  281.     return;
  282.     
  283.   if (chars == NULL)
  284.     XtErrorMsg ("noChars", "FontviewWidget", "Error",
  285.                 "Can't typeset a character with `chars' null", NULL, 0);
  286.  
  287.   /* We have to trust that `chars' really is an array that is long
  288.      enough for all possible character codes.  */
  289.   c = chars[code] ? : read_char (*font, code);
  290.   
  291.   /* If the character doesn't exist, return.  */
  292.   if (c == NULL)
  293.     return;
  294.  
  295.   bitmap_info = CHAR_BITMAP_INFO (*c);
  296.  
  297.   /* Figure out where we would be horizontally if we put this character
  298.      on the same line as the current one.  */
  299.   test_x += CHAR_SET_WIDTH (bitmap_info);
  300.   kern = current == NULL
  301.          ? 0.0 
  302.          : POINTS_TO_PIXELS (tfm_get_kern (CHAR_TFM_INFO (*current), code),
  303.                              fw->fontview.resolution);
  304.   test_x += kern;
  305.  
  306.   /* If that's too far, put it on the next line.  */
  307.   if (test_x >= width)
  308.     {
  309.       current_pos.x = 0;
  310.       current_pos.y += fw->fontview.line_space;
  311.       
  312.       /* We've moved from the baseline of the old line (the one that's
  313.          full) to the baseline of the new one (that we're about to start
  314.          typesetting on).  Check if the descender fits in the window.  */
  315.       if (current_pos.y + (1 - HEIGHT_PERCENT) * fw->fontview.line_space
  316.           >= height)
  317.         {
  318.           /* Go back to the top of the window.  */
  319.           current_pos.y = HEIGHT_PERCENT * fw->fontview.line_space;
  320.           
  321.           /* We want to set the pixmap to all zero bits, since we use
  322.              XCopyPlane to do the drawing.  We assume the foreground
  323.              pixel is zero when we come in.  */
  324.           XFillRectangle (d, fw->label.pixmap, gc, 0, 0, width, height);
  325.           
  326.           /* Update the display if necessary.  */
  327.           if (XtIsRealized (fw))
  328.             XCopyPlane (d, fw->label.pixmap, XtWindow (fw),
  329.                         fw->label.normal_GC,
  330.                         0, 0, width, height, 0, 0, 1L);
  331.         }
  332.     }
  333.   
  334.   /* OK, draw the new character with its origin at the current position.  */
  335.   current_pos.x += kern + CHAR_LSB (bitmap_info);
  336.  
  337.   pixmap = bitmap_to_pixmap (d, gc, CHAR_BITMAP (bitmap_info));
  338.  
  339.   /* Update the parent pixmap and, if necessary, the display.  */
  340.   final_y = MAX (current_pos.y - CHAR_MAX_ROW (bitmap_info), 0);
  341.  
  342.   XCopyArea (d, pixmap, fw->label.pixmap, gc, 0, 0,
  343.              CHAR_BITMAP_WIDTH (bitmap_info),
  344.              CHAR_BITMAP_HEIGHT (bitmap_info),
  345.              current_pos.x, final_y);
  346.   if (XtIsRealized (fw))
  347.     XCopyPlane (d, pixmap, XtWindow (fw), fw->label.normal_GC, 0, 0,
  348.                 CHAR_BITMAP_WIDTH (bitmap_info),
  349.                 CHAR_BITMAP_HEIGHT (bitmap_info),
  350.                 current_pos.x, final_y, 1L);
  351.  
  352.   XSetForeground (d, gc, 0L);
  353.   XFreePixmap (d, pixmap);
  354.  
  355.   current_pos.x += CHAR_BITMAP_WIDTH (bitmap_info) + CHAR_RSB (bitmap_info);
  356.   fw->fontview.current_pos = current_pos;
  357.   fw->fontview.current_char = c;
  358. }
  359.  
  360.  
  361.  
  362. /* Utilities.  */
  363.  
  364. /* Convert the bitmap B to a Pixmap on the display D, and return it.  We
  365.    use the graphics context GC for drawing.  We assume its initial
  366.    foreground is 0.  When we exit, it's 1.  */
  367.  
  368. static Pixmap
  369. bitmap_to_pixmap (Display *d, GC gc, bitmap_type b)
  370. {
  371.   unsigned row;
  372.   XSegment *save_segment_list;
  373.   XSegment *segment_list = NULL;
  374.   unsigned nsegments = 0;
  375.   unsigned height = BITMAP_HEIGHT (b);
  376.   unsigned width = BITMAP_WIDTH (b);
  377.   Pixmap pixmap
  378.     = XCreatePixmap (d, DefaultRootWindow (d), width, height, DEPTH);
  379.  
  380.   if (pixmap == None)
  381.     XtErrorMsg ("noPixmap", "FontviewWidget", "Error",
  382.                 "Can't allocate pixmap to show character", NULL, 0);
  383.  
  384.   /* Clear the new pixmap to all zeros.  */
  385.   XFillRectangle (d, pixmap, gc, 0, 0, width, height);
  386.   
  387.   /* Draw lines through consecutive black pixels on each scanline.  This
  388.      is a simplification of the code in `gnuw/Bitmap.c'.  */
  389.   for (row = 0; row < BITMAP_HEIGHT (b); row++)
  390.     {
  391.       unsigned start;
  392.       boolean done = false;
  393.       one_byte *row_data = BITMAP_ROW (b, row);
  394.       unsigned *transitions = bitmap_find_transitions (row_data, width);
  395.       unsigned *save_transitions = transitions;
  396.       
  397.       /* We must perform the test on `done' before dereferencing
  398.          `transitions' in the increment step of the loop, because if we
  399.          are indeed done, `transitions' may point to garbage.  */
  400.       for (start = *transitions++;
  401.            start != width + 1;
  402.            start = done ? width + 1 : *transitions++)
  403.         {
  404.           XSegment *s;
  405.           unsigned end = *transitions++;
  406.           
  407.           /* This test is true if the row ends with black.  */
  408.           if (end == width + 1) 
  409.             {
  410.               end--;
  411.               done = true;
  412.             }
  413.           
  414.           XRETALLOC (segment_list, ++nsegments, XSegment);
  415.           s = &segment_list[nsegments - 1];
  416.           s->x1 = start;
  417.           s->x2 = end - 1; /* `end' is at a white pixel; don't draw it.  */
  418.           s->y1 = s->y2 = row;
  419.         }
  420.       free (save_transitions);
  421.     }
  422.  
  423.   /* It's unlikely we'll ever exceed this, but just to be safe.  */
  424.   #define MAX_NSEGMENTS 4000
  425.   save_segment_list = segment_list;
  426.   XSetForeground (d, gc, 1L);
  427.   while (nsegments > MAX_NSEGMENTS)
  428.     {
  429.       XDrawSegments (d, pixmap, gc, segment_list, MAX_NSEGMENTS);
  430.       nsegments -= MAX_NSEGMENTS;
  431.       segment_list += MAX_NSEGMENTS;
  432.     }
  433.   XDrawSegments (d, pixmap, gc, segment_list, nsegments);
  434.   
  435.   free (save_segment_list);
  436.   
  437.   return pixmap;
  438. }
  439.  
  440.  
  441. /* Extract the character code of a pressed key from the event E.  I
  442.    can't see any way to tell how big the buffer might be that
  443.    XLookupString returns, so we just have to hope that what we allocate
  444.    is enough.  We set FOUND if we actually found a character code, as
  445.    opposed to just, say, a modifier key being pressed.  */
  446.  
  447. #define KEY_BUFFER_SIZE 128
  448.  
  449.  
  450. static charcode_type
  451. find_keycode (XEvent *e, boolean *found)
  452. {
  453.   char key_buffer[KEY_BUFFER_SIZE];
  454.   charcode_type ret = 75; /* Default random return value.  */
  455.   int length 
  456.      = XLookupString (&e->xkey, key_buffer, KEY_BUFFER_SIZE, NULL, NULL);
  457.  
  458.   switch (length)
  459.     {
  460.     case 0:
  461.       /* We get here if the user presses just a modifier key.  */
  462.       *found = false;
  463.       break;
  464.       
  465.     case 1:
  466.       *found = true;
  467.       ret = *key_buffer;
  468.       break;
  469.     
  470.     default:
  471.       XtErrorMsg ("strangeKey", "FontviewWidget", "Error",
  472.                   "Can't handle multicharacter key string", NULL, 0);
  473.     }
  474.  
  475.   return ret;
  476. }
  477.